/**
 * @file qq_ui.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"

#if USE_LV_WATCH_QQ != 0
/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void qq_msg_time_start_update(lv_obj_t * cont);
static uint32_t qq_voice_msg_record_buffer_stop_req(void);
/**********************
 *  STATIC VARIABLES
 **********************/
static uint32_t qq_friend_update_seq = 0;
static uint32_t qq_friend_startindex = 0;
//static uint32_t qq_lastmsg_time = 0;
//static uint32_t qq_lastmsg_random = 0;
static lv_signal_cb_t old_listscrl_signal;

const struct {
    char * ex_desc;
    char * ex_path;
    uint8_t code;
} qq_expression_list[] = {
    {"[惊讶]", "R:/png/qq/icon_qq_ex_jy.png", 0},
    {"[撇嘴]", "R:/png/qq/icon_qq_ex_pz.png", 1},
    {"[色]", "R:/png/qq/icon_qq_ex_se.png", 2},
    {"[发呆]", "R:/png/qq/icon_qq_ex_fd.png", 3},
    {"[得意]", "R:/png/qq/icon_qq_ex_dy.png", 4},
    {"[流泪]", "R:/png/qq/icon_qq_ex_ll.png", 5},
    {"[害羞]", "R:/png/qq/icon_qq_ex_hx.png", 6},
    {"[闭嘴]", "R:/png/qq/icon_qq_ex_bz.png", 7},
    {"[睡]", "R:/png/qq/icon_qq_ex_shui.png", 8},
    {"[大哭]", "R:/png/qq/icon_qq_ex_dk.png", 9},
    {"[尴尬]", "R:/png/qq/icon_qq_ex_gg.png", 10},
    {"[发怒]", "R:/png/qq/icon_qq_ex_fn.png", 11},
    {"[调皮]", "R:/png/qq/icon_qq_ex_tp.png", 12},
    {"[呲牙]", "R:/png/qq/icon_qq_ex_cy.png", 13},
    {"[微笑]", "R:/png/qq/icon_qq_ex_wx.png", 14},
    {"[难过]", "R:/png/qq/icon_qq_ex_ng.png", 15},
    {"[酷]", "R:/png/qq/icon_qq_ex_kuk.png", 16},
    {"[抓狂]", "R:/png/qq/icon_qq_ex_zk.png", 18},
};
/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
***********************/

void qq_get_my_friend_list(void)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_set_hidden(ext->leds_content, true);
    qq_create_bg_cont(ext->friend, LV_OPA_90, WATCH_TEXT_ID_QQ_GET_FRIENDS);

#if QQ_UI_TEST
    static uint8_t over = 0;
    Hal_Timer_Start(1000, qq_get_friends_timer_cb, &over, false);
#else
    watch_qq_get_friend_list_req_t * get_friend_listreq = lv_mem_alloc(sizeof(watch_qq_get_friend_list_req_t));
    get_friend_listreq->update_seq = 0;
    get_friend_listreq->start_friendindex = 0;
    get_friend_listreq->get_friendcnt = MMI_QQ_GET_FRIEND_CNT_ONCE;
    watch_qq_get_friend_list_req(get_friend_listreq);
#endif
}

bool qq_list_obj_is_label(lv_obj_t * obj)
{
    lv_obj_type_t type;
    lv_obj_get_type(obj, &type);
    uint8_t cnt;
    for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {
        if(type.type[cnt] == NULL) break;
        if(!strcmp(type.type[cnt], "lv_label")) return true;
    }
    return false;
}

lv_res_t qq_friend_listscrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)
{
    lv_obj_t * list = lv_obj_get_parent(scrl);
    if(LV_SIGNAL_DRAG_THROW_BEGIN == sign) {
        if(lv_page_on_edge(list, LV_PAGE_EDGE_BOTTOM)) {
            lv_obj_t * obj = lv_obj_get_child(scrl, NULL);
            if(!qq_list_obj_is_label(obj)) {
                lv_qq_obj_ext_t * ext = qq_get_ext();
                qq_create_bg_cont(ext->friend, LV_OPA_90, WATCH_TEXT_ID_QQ_PULLING_DATA);
#if QQ_UI_TEST
                static uint8_t over = 1;
                Hal_Timer_Start(1000, qq_get_friends_timer_cb, &over, false);
#else
                watch_qq_get_friend_list_req_t * get_friend_listreq = lv_mem_alloc(sizeof(watch_qq_get_friend_list_req_t));
                get_friend_listreq->update_seq = 0;//qq_friend_update_seq;
                get_friend_listreq->start_friendindex = qq_friend_startindex;
                get_friend_listreq->get_friendcnt = MMI_QQ_GET_FRIEND_CNT_ONCE;
                watch_qq_get_friend_list_req(get_friend_listreq);
#endif
            }
        }
    }
    return old_listscrl_signal(scrl, sign, param);
}

void qq_create_friends_list(watch_qq_get_friend_list_cnf_t * friend)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_friend_update_seq = friend->update_seq;
    qq_friend_startindex = friend->next_friendindex;
    printf("%s: seq = %d start_index=%d\n", __FUNCTION__, qq_friend_update_seq,  qq_friend_startindex);
    lv_obj_t * cont = lv_obj_get_child(ext->friend, NULL);
    if(ext->friend_list) {
        lv_obj_del(cont);
    } else {
        lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
        lv_obj_clean(cont);
        lv_obj_t * img = qq_create_back_img(cont, QQ_FRIEND_LIST);
        lv_obj_t * list = qq_create_list(cont);
        ext->friend_list = list;
        lv_obj_set_size(list, LV_HOR_RES - QQ_PAD_HOR * 2, LV_VER_RES - lv_obj_get_height(img) - QQ_PAD_VER * 2);
        lv_obj_set_pos(list, QQ_PAD_HOR, lv_obj_get_height(img) + QQ_PAD_VER);
        lv_page_set_edge_flash(list, true);
        lv_obj_set_style_local_bg_color(list, LV_LIST_PART_EDGE_FLASH, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_opa(list, LV_LIST_PART_EDGE_FLASH, LV_STATE_DEFAULT, LV_OPA_20);
        lv_obj_t * scrl = lv_page_get_scrl(list);
        old_listscrl_signal = lv_obj_get_signal_cb(scrl);
        lv_obj_set_signal_cb(scrl, qq_friend_listscrl_signal);
    }
    watch_qq_user_info_t * node = (watch_qq_user_info_t *)_lv_ll_get_head(&friend->user_infos_ll);
    qq_friend_btn_ext_t * btn_ext;
    lv_obj_t * btn;
    char * path = NULL;
    while(node) {
        if(node->remark)
            btn = qq_list_add(ext->friend_list, ICON_QQ_DEF_HEAD, node->remark, NULL, LIST_TYPE_MY_FRIENDS);
        else
            btn = qq_list_add(ext->friend_list, ICON_QQ_DEF_HEAD, node->nickname, NULL, LIST_TYPE_MY_FRIENDS);
        path = watch_qq_get_friend_head_path(node->openid);
        if(path != NULL) {
            lv_obj_t * head_img = lv_obj_get_child_back(btn, NULL);
            lv_img_set_src(head_img, path);
            lv_mem_free(path);
        }
        btn_ext = qq_btn_allocate_ext(btn, node);
        LV_ASSERT_MEM(btn_ext);
        lv_obj_set_event_cb(btn, qq_my_friend_list_btn_event_cb);
        node = (watch_qq_user_info_t *)_lv_ll_get_next(&friend->user_infos_ll, node);
    }

    if(friend->getover == 1) {
        lv_obj_t * label = lv_label_create(ext->friend_list, NULL);
        lv_obj_align(label, lv_page_get_scrollable(ext->friend_list), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
        lv_page_glue_obj(label, true);
        lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
        lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_16);
        lv_label_set_text_id(label, WATCH_TEXT_ID_QQ_NO_MORE_DATA);
    }
}

qq_friend_btn_ext_t * qq_btn_allocate_ext(lv_obj_t * btn, watch_qq_user_info_t * node)
{
    qq_friend_btn_ext_t  * btn_ext = (qq_friend_btn_ext_t *)lv_obj_allocate_ext_attr(btn, sizeof(qq_friend_btn_ext_t));
    memset(&btn_ext->info, 0, sizeof(watch_qq_user_info_t));
    if(node->headurl) {
        btn_ext->info.headurl = lv_strdup(node->headurl);
    }
    if(node->nickname) {
        btn_ext->info.nickname = lv_strdup(node->nickname);
    }
    if(node->remark) {
        btn_ext->info.remark = lv_strdup(node->remark);
    }
    strncpy(btn_ext->info.openid, node->openid, 64);
    strncpy(btn_ext->info.qqid, node->qqid, strlen(node->qqid));
    btn_ext->info.contact_time = node->contact_time;
    return btn_ext;
}

void qq_del_friend_result_timer_cb(lv_anim_t * anim)
{
    lv_obj_t * label = (lv_obj_t *)anim->var;
    uint16_t txtId = lv_watch_get_free_num(label);
    lv_obj_del(lv_obj_get_parent(label));
    if(txtId == WATCH_TEXT_ID_DEL_SUCCESS) {
        printf("%s: delete friend list btn\n", __FUNCTION__);
        lv_qq_obj_ext_t * ext = qq_get_ext();
        lv_obj_del(lv_obj_get_child(ext->friend, NULL));
    }
}

void qq_del_friend_result(uint8_t result)
{
    printf("%s:result = %d\n", __FUNCTION__, result);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * cont = lv_obj_get_child(ext->friend, NULL);
    lv_obj_set_height(cont, LV_VER_RES / 5);
    lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_t * label = lv_obj_get_child(cont, NULL);
    if(result == WATCH_QQ_OK) {
        lv_label_set_text_id(label, WATCH_TEXT_ID_DEL_SUCCESS);
        watch_qq_user_info_t * info = lv_watch_get_free_ptr(cont);
        watch_qq_del_friend(info->qqid);
        lv_list_remove(ext->friend_list, lv_list_get_btn_index(ext->friend_list, ext->friend_list_act_btn));
        ext->friend_list_act_btn = NULL;
        qq_delete_recent_contact(ext->recent_list, info->openid);
    } else {
        lv_label_set_text_id(label, WATCH_TEXT_ID_QQ_DEL_FAILED);
    }
    lv_obj_realign(label);
    lv_anim_t a = {0};
    lv_anim_init(&a);
    lv_anim_set_var(&a, label);
    lv_anim_set_ready_cb(&a, (lv_anim_ready_cb_t)qq_del_friend_result_timer_cb);
    lv_anim_set_repeat_count(&a, 1);
    lv_anim_set_time(&a, 1000);
    lv_anim_start(&a);
}

void qq_del_friend_confirm_btn_event_cb(lv_obj_t * btnm, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    char * txt = (char *)lv_btnmatrix_get_active_btn_text(btnm);
    if(strcmp(txt, (char *)lv_lang_get_text(WATCH_TEXT_ID_OK)) == 0) {
        lv_obj_t * msgbox = lv_obj_get_parent(btnm);
        lv_obj_t * cont = lv_obj_get_parent(msgbox);
        lv_obj_del(msgbox);
        lv_obj_t * label = lv_label_create(cont, NULL);
        lv_label_set_text_id(label, WATCH_TEXT_ID_QQ_OPERATING);
        lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);

#if QQ_UI_TEST
        Hal_Timer_Start(1000, qq_delete_friend_timer_cb, NULL, false);
#else
        watch_qq_user_info_t * info = lv_watch_get_free_ptr(cont);
        watch_qq_delete_friend_req_t * del_friend_req = lv_mem_alloc(sizeof(watch_qq_delete_friend_req_t));
        _lv_memset_00(del_friend_req, sizeof(watch_qq_delete_friend_req_t));
        del_friend_req->delete_type = WATCH_QQ_DELETE_TYPE_FROM_BOTH_SIDE;
        memcpy(del_friend_req->delete_openid, info->openid, 64);
        watch_qq_delete_friend_req(del_friend_req);
#endif
    } else {
        lv_obj_del(lv_obj_get_parent(lv_obj_get_parent(btnm)));
    }
}

lv_obj_t * qq_msg_list_create(lv_obj_t * par, uint16_t width, uint16_t height)
{
    lv_obj_t * list = lv_list_create(par, NULL);
    qq_msg_list_ext_t * ext = lv_obj_allocate_ext_attr(list, sizeof(qq_msg_list_ext_t));
    ext->buffer = NULL;
    ext->record_cont = NULL;
    memset(&ext->voice_playing_anim, 0, sizeof(lv_anim_t));
    ext->pressing = false;
    ext->getting_msg = true;
    ext->btn_cnt = 0;
    lv_obj_set_size(list, width, height);
    lv_page_set_scrollbar_mode(list, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_style_local_bg_opa(list, LV_PAGE_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
    lv_obj_set_style_local_border_opa(list, LV_PAGE_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
    lv_obj_set_style_local_outline_width(list, LV_PAGE_PART_BG, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_bottom(list, LV_PAGE_PART_SCROLLABLE, LV_STATE_DEFAULT, 4);
    lv_obj_set_style_local_pad_top(list, LV_PAGE_PART_SCROLLABLE, LV_STATE_DEFAULT, 2);
    lv_obj_set_style_local_pad_inner(list, LV_PAGE_PART_SCROLLABLE, LV_STATE_DEFAULT, 8);
    return list;
}

static void qq_msg_list_voiceplaying_anim(lv_anim_t * a)
{
    lv_obj_t * play_img = (lv_obj_t *)a->var;
    lv_obj_t * bubble_obj = lv_obj_get_parent(lv_obj_get_parent(play_img));
    uint8_t direction = QQ_MSG_IS_MSG_FROM_SERVICE(voice_msg_get_user_num(bubble_obj));
    uint32_t anim_step = lv_watch_get_free_num(play_img);
    if(3 == anim_step) {
        if(1 == direction) {
            lv_img_set_src(play_img, ICON_QQ_PLAYING_01);
        } else {
            lv_img_set_src(play_img, ICON_QQ_MY_PLAYING_01);
        }
        lv_watch_set_free_num(play_img, 1);
    } else if(2 == anim_step) {
        if(1 == direction) {
            lv_img_set_src(play_img, ICON_QQ_PLAYING_03);
        } else {
            lv_img_set_src(play_img, ICON_QQ_MY_PLAYING_03);
        }
        lv_watch_set_free_num(play_img, 3);
    } else if(1 == anim_step) {
        if(1 == direction) {
            lv_img_set_src(play_img, ICON_QQ_PLAYING_02);
        } else {
            lv_img_set_src(play_img, ICON_QQ_MY_PLAYING_02);
        }
        lv_watch_set_free_num(play_img, 2);
    }
}

static void qq_msg_create_voice_anim(lv_obj_t * play_img, qq_msg_list_ext_t * list_ext)
{
    printf("%s\n", __FUNCTION__);
    lv_watch_set_free_num(play_img, 3);

    lv_anim_init(&list_ext->voice_playing_anim);
    lv_anim_set_var(&list_ext->voice_playing_anim, play_img);
    lv_anim_set_start_cb(&list_ext->voice_playing_anim, (lv_anim_ready_cb_t)qq_msg_list_voiceplaying_anim);
    lv_anim_set_repeat_count(&list_ext->voice_playing_anim, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_time(&list_ext->voice_playing_anim, 400);
    lv_anim_start(&list_ext->voice_playing_anim);
}

static void qq_msg_voice_over_task_cb(lv_task_t * task)
{
    printf("%s: for chat list\n", __FUNCTION__);
    if(NULL == task) return;

    Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    if(ext->msg_list == NULL) return;
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)task->user_data;
    if(NULL == list_ext) return;
    if(NULL == list_ext->voice_playing_anim.var) {
        printf("%s: anim var NULL\n", __FUNCTION__);
        return;
    }

    lv_anim_del(list_ext->voice_playing_anim.var, list_ext->voice_playing_anim.exec_cb);
    lv_obj_t * voice_obj = lv_obj_get_parent(lv_obj_get_parent(list_ext->voice_playing_anim.var));
    uint32_t free_num = lv_watch_get_free_num(voice_obj);
    uint8_t direction = QQ_MSG_IS_MSG_FROM_SERVICE(free_num);
    if(direction) {
        lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_PLAYING_03);
    } else {
        lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_MY_PLAYING_03);
    }
    list_ext->voice_playing_anim.var = NULL;

    qq_msg_voice_obj_ext_t * voice_ext = lv_obj_get_ext_attr(voice_obj);
    if(!QQ_MSG_IS_LOCAL_FLAG(free_num)) {
        if(voice_ext->voice_buffer) {
            lv_mem_free(voice_ext->voice_buffer);
            voice_ext->voice_buffer = NULL;
        }
        lv_watch_set_free_num(voice_obj, QQ_MSG_SET_UNLOAD_FLAG(free_num));
    }
    watch_set_suspend_enable(true, ACT_ID_QQ_MAIN, false);
}

static void qq_msg_voice_over_cb(void * para)
{
    lv_task_t * over_task = lv_task_create(qq_msg_voice_over_task_cb, 10, LV_TASK_PRIO_MID, para);
    lv_task_once(over_task);
}

static void qq_msg_play_voice(lv_obj_t * obj, qq_msg_list_ext_t * list_ext)
{
    qq_msg_voice_obj_ext_t * voice_ext = lv_obj_get_ext_attr(obj);
    void * buffer = voice_ext->voice_buffer;
    uint32_t len = voice_ext->voice_size;
    printf("%s: buffer %p, len %d\n", __FUNCTION__, buffer, len);
    watch_set_suspend_enable(false, ACT_ID_QQ_MAIN, false);
    Hal_Audio_Manage_Start_Req(AUDIO_CTRL_PRIORITY_5, voice_msg_audio_ctrl_callback);
    Voice_Msg_Play_Onetime(buffer,
                           len,
                           query_current_volume(),
                           qq_msg_voice_over_cb,
                           list_ext);
}

static void qq_msg_play_end(uint32_t len)
{
#ifdef BUILD_IN_PC_SIMULATOR /*for pc test*/
    if(0 == len) {
        // file
        voice_msg_test_file_play_end();
    } else {
        // buffer
        voice_msg_test_tone_play_end();
    }
#else
    if(0 == len) {
        // file
        Hal_NFFS_File_Play_End();
    } else {
        // buffer
        Hal_Tone_Play_End();
    }
#endif
}

void qq_stop_play_voice(lv_qq_obj_ext_t * ext)
{
    if(ext->msg_list == NULL) return;
    qq_msg_list_ext_t * list_ext = lv_obj_get_ext_attr(ext->msg_list);
    if(list_ext->voice_playing_anim.var) {
        lv_obj_t * old_img = lv_obj_get_parent(list_ext->voice_playing_anim.var);
        lv_obj_t * old_obj = lv_obj_get_parent(old_img);
        qq_msg_voice_obj_ext_t * old_voice_ext = lv_obj_get_ext_attr(old_obj);
        uint32_t voice_len = old_voice_ext->voice_size;
        printf("%s: stop the current voice, size %d\n", __FUNCTION__, voice_len);
        qq_msg_play_end(voice_len);
        Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
        lv_anim_del(list_ext->voice_playing_anim.var, NULL);
        if(QQ_MSG_IS_MSG_FROM_SERVICE(lv_watch_get_free_num(old_obj))) {
            lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_PLAYING_03);
        } else {
            lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_MY_PLAYING_03);
        }
        list_ext->voice_playing_anim.var = NULL;
    }
}

void qq_play_voice(lv_obj_t * img, qq_msg_list_ext_t * list_ext)
{
    lv_obj_t * play_img = lv_obj_get_child_back(img, NULL);
    lv_obj_t * obj = lv_obj_get_parent(img);
    qq_msg_voice_obj_ext_t * voice_ext = lv_obj_get_ext_attr(obj);
    void * voice_buf = voice_ext->voice_buffer;
    printf("%s: voice_buf %p, anim var %p\n",
           __FUNCTION__, voice_buf, list_ext->voice_playing_anim.var);
    if(list_ext->voice_playing_anim.var) {
        lv_obj_t * old_img = lv_obj_get_parent(list_ext->voice_playing_anim.var);
        lv_obj_t * old_obj = lv_obj_get_parent(old_img);
        qq_msg_voice_obj_ext_t * old_voice_ext = lv_obj_get_ext_attr(old_obj);
        uint32_t voice_len = old_voice_ext->voice_size;
        printf("%s: stop the current voice, size %d\n", __FUNCTION__, voice_len);
        qq_msg_play_end(voice_len);
        Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
        if(list_ext->voice_playing_anim.var != play_img) {
            lv_anim_del(list_ext->voice_playing_anim.var, NULL);
            if(QQ_MSG_IS_MSG_FROM_SERVICE(lv_watch_get_free_num(old_obj))) {
                lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_PLAYING_03);
            } else {
                lv_img_set_src(list_ext->voice_playing_anim.var, ICON_QQ_MY_PLAYING_03);
            }
            list_ext->voice_playing_anim.var = NULL;
            if(voice_buf) {
                qq_msg_create_voice_anim(play_img, list_ext);
            }
        }
        if(voice_buf) {
            qq_msg_play_voice(obj, list_ext);
        }
    } else if(voice_buf) {
        qq_msg_create_voice_anim(play_img, list_ext);
        qq_msg_play_voice(obj, list_ext);
    }
}

void qq_msg_list_voicebtn_event_cb(lv_obj_t * img, lv_event_t event)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)lv_obj_get_ext_attr(ext->msg_list);
    lv_obj_t * list_obj = lv_obj_get_parent(img);
    qq_msg_voice_obj_ext_t * voice_ext = lv_obj_get_ext_attr(list_obj);

    if(LV_EVENT_PRESSED == event) {
        list_ext->pressing = true;
    } else if((true == list_ext->pressing) && (LV_EVENT_CLICKED == event)) {
        if(NULL == list_ext) return;
        list_ext->pressing = false;
        uint32_t free_num = lv_watch_get_free_num(list_obj);
        if(QQ_MSG_IS_UNLOAD_FLAG(free_num)) {
            watch_qq_get_data_req_t * get_data_req = lv_mem_alloc(sizeof(watch_qq_get_data_req_t));
            get_data_req->url = lv_strdup(voice_ext->url);
            qq_add_get_data_info(QQ_DATA_MSG_VOICE, 0, get_data_req->url);
            watch_qq_get_data_req(get_data_req);
        } else {
            qq_play_voice(img, list_ext);
        }
    } else if(LV_EVENT_DELETE == event) {
        if(voice_ext->voice_buffer) {
            lv_mem_free(voice_ext->voice_buffer);
            voice_ext->voice_buffer = NULL;
        }
        if(voice_ext->url) {
            lv_mem_free(voice_ext->url);
            voice_ext->url = NULL;
        }
        printf("%s: voice msg obj deleted, free ext data!!\n", __FUNCTION__);
    }
}

lv_obj_t * qq_msg_list_add(lv_obj_t * list, qq_msg_desc_t * msg_desc)
{
    qq_msg_list_ext_t * list_ext = lv_obj_get_ext_attr(list);
    lv_obj_t * scrl = lv_page_get_scrl(list);
    printf("%s: msg type %d\n", __FUNCTION__,  msg_desc->type);

    if(msg_desc->direction == 1) {
    	lv_obj_t * last_obj = lv_obj_get_child(scrl, NULL);
        while(last_obj) {
        	if(QQ_MSG_IS_MSG_FROM_SERVICE(lv_watch_get_free_num(last_obj)) &&
                	msg_desc->seq_id == QQ_MSG_GET_SEQ_ID(lv_watch_get_free_num(last_obj))) {
                printf("%s: same seqid %d,throww it!\n", __FUNCTION__, msg_desc->seq_id);
            	return NULL;
            }
            last_obj = lv_obj_get_child(scrl, last_obj);
        }
    }
    uint32_t free_num = 0;
    QQ_MSG_SET_MSG_TYPE(free_num, msg_desc->type);
    if(1 == msg_desc->direction) {
        QQ_MSG_SET_MSG_FROM_SERVICE(free_num);
    }
    if(1 == msg_desc->sending) {
        QQ_MSG_SET_SENDING_FLAG(free_num);
    }
    if(0 != msg_desc->seq_id) {
        QQ_MSG_SET_SEQ_ID(free_num, msg_desc->seq_id);
    }
    if(0 == msg_desc->local_msg) {
        QQ_MSG_SET_UNLOAD_FLAG(free_num);
    } else {
        QQ_MSG_SET_LOCAL_FLAG(free_num);
    }

    lv_obj_t * obj = lv_cont_create(list, NULL);
    lv_watch_set_free_num(obj, free_num);
    list_ext->btn_cnt++;
    lv_obj_set_style_local_bg_opa(obj, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
    lv_obj_set_style_local_pad_left(obj, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 2);
    lv_obj_set_style_local_pad_right(obj, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 2);
    lv_obj_set_style_local_pad_inner(obj, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 8);
    lv_cont_set_fit2(obj, LV_FIT_NONE, LV_FIT_TIGHT);
    lv_obj_set_width(obj, lv_obj_get_width(scrl));
    lv_page_glue_obj(obj, true);
    lv_cont_set_layout(obj, LV_LAYOUT_OFF);

    lv_obj_t * time_label = NULL;
    if(msg_desc->time != 0) { /*time*/
        char time_str[16];
        qq_get_timestr_from_timestamp(msg_desc->time, time_str, 16);
        time_label = lv_label_create(obj, NULL);
        lv_label_set_text(time_label, time_str);
        lv_watch_set_free_num(time_label, msg_desc->time);
        lv_obj_set_style_local_text_font(time_label, LV_LABEL_PART_MAIN,  LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_16);
        lv_obj_set_style_local_text_color(time_label, LV_LABEL_PART_MAIN,  LV_STATE_DEFAULT, LV_COLOR_GRAY);
        lv_obj_align(time_label, obj, LV_ALIGN_IN_TOP_MID, 0, 0);
    }

    lv_coord_t obj_h = 0;
    if(time_label)
        obj_h = lv_obj_get_height(time_label) + lv_obj_get_style_pad_inner(obj, LV_STATE_DEFAULT);
    else
        obj_h = lv_obj_get_style_pad_inner(obj, LV_STATE_DEFAULT);

    if(msg_desc->type == QQ_MSG_TYPE_TEXT || msg_desc->type == QQ_MSG_TYPE_PHOTO || msg_desc->type == QQ_MSG_TYPE_OTHER) { /*text || photo*/
        lv_obj_t * chat_cont = lv_cont_create(obj, NULL);
        lv_obj_set_style_local_pad_top(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
        lv_obj_set_style_local_pad_left(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
        lv_obj_set_style_local_pad_bottom(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
        lv_obj_set_style_local_pad_right(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
        lv_obj_set_style_local_radius(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 30);
        lv_cont_set_fit(chat_cont, true);
        lv_obj_t * chat_label = lv_label_create(chat_cont, NULL);
        lv_obj_set_style_local_text_color(chat_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        if(msg_desc->type == QQ_MSG_TYPE_TEXT) {

            char * text = msg_desc->data;
            lv_label_set_text(chat_label, msg_desc->data);
            lv_coord_t width = _lv_txt_get_width(text,
                                                 strlen(text),
                                                 LV_THEME_WATCH_NIGHT_FONT_SMALL,
                                                 0,
                                                 LV_TXT_FLAG_NONE);
            if(width > LV_HOR_RES * 3 / 4) {
                lv_label_set_long_mode(chat_label, LV_LABEL_LONG_BREAK);
                lv_obj_set_width(chat_label, LV_HOR_RES * 3 / 4);
            }
        } else if(msg_desc->type == QQ_MSG_TYPE_PHOTO) {
            lv_label_set_text(chat_label, "[图片]");
        } else {
            lv_label_set_text(chat_label, "[不支持的消息]");
        }

        obj_h = obj_h + lv_obj_get_style_pad_inner(obj, LV_STATE_DEFAULT);
        if(msg_desc->direction == 1) {
            lv_obj_align(chat_cont, obj, LV_ALIGN_IN_TOP_LEFT, 7, obj_h);
            lv_obj_set_style_local_bg_color(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, QQ_COLOR_FRIEND_BUBBLE);
        } else {
            lv_obj_align(chat_cont, obj, LV_ALIGN_IN_TOP_RIGHT, -7, obj_h);
            lv_obj_set_style_local_bg_color(chat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,  QQ_COLOR_MY_BUBBLE);
        }
        lv_obj_set_click(obj, false);
        lv_obj_set_click(chat_cont, false);
    } else if(msg_desc->type == QQ_MSG_TYPE_EXPRESSION) { /*expression*/
        lv_obj_t * ex_bg = lv_img_create(obj, NULL);
        lv_img_set_src(ex_bg, ICON_QQ_EX_BG);
        lv_obj_t * ex_img = lv_img_create(ex_bg, NULL);
        lv_img_set_src(ex_img, qq_expression_list[msg_desc->ex_index].ex_path);
        lv_obj_align(ex_img, ex_bg, LV_ALIGN_CENTER, 0, 0);
        if(msg_desc->direction == 1) {
            lv_img_set_src(ex_bg, ICON_QQ_EX_BG_OTHER);
            lv_obj_align(ex_bg, obj, LV_ALIGN_IN_TOP_LEFT, 10, obj_h);
        } else {
            lv_obj_align(ex_bg, obj, LV_ALIGN_IN_TOP_RIGHT, -10, obj_h);
        }
        lv_obj_set_click(obj, false);
        lv_obj_set_click(ex_bg, false);
    } else if(msg_desc->type == QQ_MSG_TYPE_VOICE) { /*voice*/
        lv_obj_t * voice_bg = lv_img_create(obj, NULL);
        qq_msg_voice_obj_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(qq_msg_voice_obj_ext_t));
        ext->url = NULL;
        ext->voice_buffer = NULL;
        ext->voice_size = 0;
        lv_obj_t * playing_img = lv_img_create(voice_bg, NULL);
        lv_obj_t * len_label = lv_label_create(voice_bg, NULL);
        lv_obj_set_style_local_text_font(len_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_14);

        if(msg_desc->local_msg == 0) {
            ext->url = msg_desc->data;
        }

        uint32_t duration = msg_desc->duration;
        if(0 == duration) {
            if(VOICE_MSG_AMR_HEAD_SIZE < msg_desc->size) {
                duration = qq_get_voice_duration(msg_desc->data, msg_desc->size);
            }
        }
        printf("%s: voice duration = %d\n", __FUNCTION__, duration);
        char len_str[4] = {0};
        snprintf(len_str, 4, "%dS", msg_desc->duration);
        lv_label_set_text(len_label, len_str);

        if(msg_desc->direction == 1) {
            lv_obj_set_style_local_text_color(len_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
            lv_img_set_src(voice_bg, ICON_QQ_VOICE_BG_OTHER);
            lv_obj_align(voice_bg, obj, LV_ALIGN_IN_TOP_LEFT, 10, obj_h);
            lv_img_set_src(playing_img, ICON_QQ_PLAYING_03);
            lv_obj_align(playing_img, voice_bg, LV_ALIGN_IN_LEFT_MID, 10, 0);
            lv_obj_align(len_label, voice_bg, LV_ALIGN_IN_RIGHT_MID, -10, 0);
        } else {
            lv_obj_set_style_local_text_color(len_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
            lv_img_set_src(voice_bg, ICON_QQ_VOICE_BG);
            lv_obj_align(voice_bg, obj, LV_ALIGN_IN_TOP_RIGHT, -10, obj_h);
            lv_img_set_src(playing_img, ICON_QQ_MY_PLAYING_03);
            lv_obj_align(playing_img, voice_bg, LV_ALIGN_IN_RIGHT_MID, -10, 0);
            lv_obj_align(len_label, voice_bg, LV_ALIGN_IN_LEFT_MID, 10, 0);
        }
        if(0 < duration && 1 == msg_desc->local_msg) {
            printf("%s: data buffer size %d\n", __FUNCTION__, msg_desc->size);
            if(msg_desc->size > VOICE_MSG_AMR_HEAD_SIZE) {
                ext->voice_size = msg_desc->size;
                ext->voice_buffer = lv_mem_alloc(msg_desc->size);
                memset(ext->voice_buffer, 0, msg_desc->size);
                memcpy(ext->voice_buffer, msg_desc->data, msg_desc->size);
            } else {
                lv_img_set_src(playing_img, ICON_VOICE_DAMAGE);
            }
        }
        lv_obj_set_click(obj, true);
        lv_obj_set_click(voice_bg, true);
        lv_obj_set_event_cb(voice_bg, qq_msg_list_voicebtn_event_cb);
        lv_obj_set_adv_hittest(voice_bg, false);
    } else {
        printf("Wrong voice msg type!\n");
        return NULL;
    }

    if(msg_desc->sending == 1) {
        lv_obj_t * msg = lv_obj_get_child(obj, NULL);
        lv_obj_t * sending = lv_img_create(obj, NULL);
        lv_img_set_src(sending, ICON_QQ_SENDING_MSG);
        lv_obj_align(sending, msg, LV_ALIGN_OUT_LEFT_MID, -lv_obj_get_width(sending) / 5, 0);
    }
    lv_list_focus_btn(list, obj);
    printf("%s: btn num = %d\n", __FUNCTION__, list_ext->btn_cnt);
    if(list_ext->btn_cnt > MMI_QQ_CHAT_MSG_BTN_MAX_CNT) {
        uint8_t i = 0;
        for(i = 0; i < list_ext->btn_cnt - MMI_QQ_CHAT_MSG_BTN_MAX_CNT; i++) {
            printf("%s: del %d btn\n", __FUNCTION__, i);
            lv_obj_del(lv_obj_get_child_back(scrl, NULL));
            list_ext->btn_cnt--;
        }
    }
    return obj;
}

static void qq_expression_tileview_event_cb(lv_obj_t * tileview, lv_event_t event)
{
    if(LV_EVENT_VALUE_CHANGED == event) {
        lv_obj_t * page_label = lv_obj_get_child(lv_obj_get_parent(tileview), tileview);
        lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
        char str[6];
        snprintf(str, 6, "(%d/%d)", ext->act_id.x + 1, ext->valid_pos_cnt);
        lv_label_set_text(page_label, str);
    }
}

void qq_send_msg(char * to_openid, qq_msg_type_t type, uint8_t ex_index,  uint8_t * buffer, uint32_t size, uint8_t duration)
{
#if QQ_UI_TEST
    Hal_Timer_Start(1000, qq_send_msg_timer_cb, NULL, false);
#else
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_msg_desc_t desc = {0};

    hal_rtc_t time;
    Hal_Rtc_Gettime(&time);
    desc.time = time_to_seconds(&time) - (8 * 3600);
    uint8_t seq_id = (uint8_t)(rand() % 255);
    uint16_t random = desc.time & (0x000000FF);
    desc.type = type;
    desc.sending = 1;
    desc.seq_id = random << 8 | seq_id;
    printf("%s: seqid = %d, desc.seq_id = %d\n", __FUNCTION__, seq_id, desc.seq_id);
    if(type == QQ_MSG_TYPE_EXPRESSION) {
        desc.data = qq_expression_list[ex_index].ex_path;
        desc.ex_index = ex_index;
    } else {
        desc.local_msg = 1;
        desc.data = buffer;
        desc.size = size;
        desc.duration = duration;
    }
    qq_msg_list_add(ext->msg_list, &desc);

    watch_qq_login_info_t * loginfo = watch_qq_get_last_login_info();
    watch_qq_send_msg_req_t * send_req = (watch_qq_send_msg_req_t *)lv_mem_alloc(sizeof(watch_qq_send_msg_req_t));
    memcpy(send_req->msg_info.from_openid, loginfo->openid, 64);
    lv_mem_free(loginfo);
    memcpy(send_req->msg_info.to_openid, to_openid, 64);
    send_req->msg_info.msg_timestamp = desc.time;
    send_req->msg_info.msg_seqid = desc.seq_id;
    send_req->msg_info.msg_elementcnt = 1;
    _lv_ll_init(&send_req->msg_info.msg_elements_ll, sizeof(watch_qq_msg_element_t));
    watch_qq_msg_element_t * node = _lv_ll_ins_tail(&send_req->msg_info.msg_elements_ll);
    if(type == QQ_MSG_TYPE_EXPRESSION) {
        node->msg_type = WATCH_QQ_MSG_TYPE_FACE;
        node->msg_content = lv_mem_alloc(sizeof(uint8_t));
        memcpy(node->msg_content, (void *) & (qq_expression_list[ex_index].code), sizeof(uint8_t));
    } else if(type == QQ_MSG_TYPE_VOICE) {
        node->msg_type = WATCH_QQ_MSG_TYPE_PTT_BIN;
        node->msg_content = lv_mem_alloc(sizeof(watch_qq_ptt_bin_msg_content_t));
        watch_qq_ptt_bin_msg_content_t * content = node->msg_content;
        content->length = size;
        content->duration = duration;
        content->pttbin = lv_mem_alloc(size);
        memset(content->pttbin, 0, size);
        memcpy(content->pttbin, buffer, size);
        lv_mem_free(buffer);
    }
    watch_qq_send_msg_req(send_req);
#endif
}

void qq_send_msg_result(uint8_t result, uint32_t time, uint16_t seqid)
{
    printf("%s result = %d seqid = %d\n", __FUNCTION__, result, seqid);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    if(ext->msg_list == NULL) return;
    lv_obj_t * list_obj = lv_obj_get_child_back(lv_page_get_scrl(ext->msg_list), NULL);
    while(list_obj) {
        uint32_t user_num = lv_watch_get_free_num(list_obj);
        if(!QQ_MSG_IS_MSG_FROM_SERVICE(user_num) && QQ_MSG_IS_SENDING_FLAG(user_num)) {
            lv_obj_t * sending = lv_obj_get_child(list_obj, NULL);
            if(sending != NULL && seqid == QQ_MSG_GET_SEQ_ID(user_num)) {
                if(result == WATCH_QQ_OK) {
                    lv_obj_del(sending);
                } else {
                    lv_img_set_src(sending, ICON_QQ_SEND_FAILED);
                }
                lv_watch_set_free_num(list_obj, QQ_MSG_CLEAR_SENDING_FLAG(user_num));
            }
        }
        list_obj = lv_obj_get_child_back(lv_page_get_scrl(ext->msg_list), list_obj);
    }

#if QQ_UI_TEST
    hal_rtc_t time_now;
    Hal_Rtc_Gettime(&time_now);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_msg_desc_t desc = {0};
    desc.type = QQ_MSG_TYPE_VOICE;
    desc.time = time_to_seconds(&time_now);
    //desc.data = //path;
    desc.size = 4;
    desc.sending = 0;
    desc.direction = 1;
    qq_msg_list_add(ext->msg_list, &desc);
#endif
}

static void qq_expression_select_event_cb(lv_obj_t * ex_img, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    uint8_t ex_index = lv_watch_get_free_num(ex_img);
    printf("%s: ex_index = %d\n", __FUNCTION__, ex_index);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * main_tileview = lv_obj_get_child(qq_get_obj(), NULL);
    lv_tileview_ext_t * tile_ext = lv_obj_get_ext_attr(main_tileview);
    watch_qq_user_info_t * info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(ext->name);

    lv_obj_t * par;
    printf("%s: x = %d\n", __FUNCTION__, tile_ext->act_id.x);
    if(tile_ext->act_id.x == 0) par = ext->recentmsg;
    else par = ext->friend;
    lv_obj_del(lv_obj_get_child(par, NULL));

    qq_send_msg(info->openid, QQ_MSG_TYPE_EXPRESSION, ex_index, NULL, 0, 0);
}

void qq_create_expression_btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * main_tileview = lv_obj_get_child(qq_get_obj(), NULL);
    lv_tileview_ext_t * tile_ext = lv_obj_get_ext_attr(main_tileview);
    lv_obj_t * par;
    printf("%s: x = %d\n", __FUNCTION__, tile_ext->act_id.x);
    if(tile_ext->act_id.x == 0) par = ext->recentmsg;
    else par = ext->friend;
    lv_obj_t * cont = qq_create_bg_cont(par, LV_OPA_COVER, 0);
    lv_obj_t * back_img = qq_create_back_img(cont, QQ_EXPRESSION);
    lv_obj_t * label = lv_label_create(cont, NULL);
    lv_label_set_text_id(label, WATCH_TEXT_ID_QQ_EXPRESSION);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_16);
    lv_obj_align(label, back_img, LV_ALIGN_OUT_RIGHT_MID,
                 (LV_HOR_RES - lv_obj_get_width(back_img) - lv_obj_get_width(label) - QQ_BACK_IMG_PAD_LEFT) / 3, -lv_obj_get_height(label) / 2);

    uint8_t page_cnt = (MMI_QQ_EXPRESSION_MAX_CNT  - 1) / 9 + 1;
    lv_obj_t * page_label = lv_label_create(cont, NULL);
    char page_str[6];
    snprintf(page_str, 6, "(1/%d)", page_cnt);
    lv_label_set_text(page_label, page_str);
    lv_obj_set_style_local_text_font(page_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_16);
    lv_obj_align(page_label, label, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    static lv_point_t valid_pos[] = {
        {0, 0}, {1, 0}, {2, 0}
    };

    lv_obj_t * tileview = lv_tileview_create(cont, NULL);
    lv_obj_set_size(tileview, LV_HOR_RES - QQ_PAD_HOR * 2, LV_VER_RES - lv_obj_get_height(back_img) - QQ_PAD_VER * 2);
    lv_obj_set_pos(tileview, QQ_PAD_HOR, lv_obj_get_height(back_img) + QQ_PAD_VER);
    lv_tileview_set_valid_positions(tileview, valid_pos, page_cnt);
    lv_tileview_set_edge_flash(tileview, true);
    lv_tileview_set_anim_time(tileview, 60);
    lv_page_set_scrollbar_mode(tileview, LV_SCROLLBAR_MODE_OFF);
    lv_page_set_edge_flash(tileview, false);
    lv_obj_set_event_cb(tileview, qq_expression_tileview_event_cb);

    lv_obj_t * ex_cont;
    lv_obj_t * ex_img;
    lv_obj_t * ex_frame;
    uint8_t j = 0;
    for(uint8_t i = 0; i < page_cnt; i++) {
        ex_cont = qq_tileview_add_tile(tileview, i);
        lv_obj_set_x(ex_cont, (LV_HOR_RES - QQ_PAD_HOR * 2) * i);
        lv_obj_set_size(ex_cont, lv_obj_get_width(tileview), lv_obj_get_height(tileview));
        lv_cont_set_layout(ex_cont, LV_LAYOUT_GRID);

        for(j = 9 * i; j < (9 * (i + 1)) ; j++) {
            ex_frame = lv_cont_create(ex_cont, NULL);
            lv_tileview_add_element(tileview, ex_frame);
            lv_obj_set_size(ex_frame, (LV_HOR_RES - QQ_PAD_HOR * 3) / 4, (LV_VER_RES - QQ_PAD_HOR * 3) / 4);
            lv_obj_set_style_local_radius(ex_frame, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
            ex_img = lv_img_create(ex_frame, NULL);
            lv_watch_set_free_num(ex_img, j);
            lv_img_set_src(ex_img, qq_expression_list[j].ex_path);
            lv_obj_align(ex_img, ex_frame, LV_ALIGN_CENTER, 0, 0);
            lv_tileview_add_element(tileview, ex_img);
            lv_obj_set_click(ex_img, true);
            lv_obj_set_event_cb(ex_img, qq_expression_select_event_cb);
            if(j == MMI_QQ_EXPRESSION_MAX_CNT - 1) break;
        }
        lv_obj_set_style_local_pad_left(ex_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_obj_get_width(ex_frame) / 4);
        lv_obj_set_style_local_pad_right(ex_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_obj_get_width(ex_frame) / 4);
        lv_obj_set_style_local_pad_inner(ex_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                         (LV_VER_RES - lv_obj_get_width(ex_frame) * 3 / 5 - 3 * lv_obj_get_width(ex_frame) - QQ_PAD_HOR * 2) / 2);
    }
}

static void qq_msg_speaking_anim(lv_anim_t * a)
{
    lv_obj_t * img = a->var;
    uint8_t step = lv_watch_get_free_num(img);
    uint8_t record = step % 3;
    switch(record) {
        case 0:
            lv_img_set_src(img, ICON_QQ_RECORD_01);
            break;
        case 1:
            lv_img_set_src(img, ICON_QQ_RECORD_02);
            break;
        case 2:
            lv_img_set_src(img, ICON_QQ_RECORD_03);
            break;
        default:
            break;
    }
    lv_watch_set_free_num(img, step + 1);
    if(0 == (step % 2)) {
        lv_obj_t * time_label;
        lv_obj_t * rec_cont = lv_obj_get_parent(img);
        if(lv_obj_count_children(rec_cont) == 1) {
            time_label = lv_label_create(rec_cont, NULL);
            lv_label_set_text(time_label, "8");
            lv_watch_set_free_num(time_label, 8);
            lv_obj_set_style_local_text_font(time_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_16);
            lv_obj_align(time_label, img, LV_ALIGN_OUT_LEFT_MID, 0, -(lv_obj_get_height(img) / 2));
        } else {
            time_label = lv_obj_get_child(rec_cont, NULL);
            uint8_t time = lv_watch_get_free_num(time_label);
            char str[2];
            if(time > 0) {
                snprintf(str, 2, "%d", time - 1);
                lv_watch_set_free_num(time_label, time - 1);
                lv_label_set_text(time_label, str);
            }
        }
    }
}

void qq_record_time_short_tip_timer_cb(lv_anim_t * anim)
{
    if(watch_is_qq_activity() == false) return;
    lv_obj_t * label = (lv_obj_t *)anim->var;
#if QQ_UI_TEST
    lv_label_set_text(label, "hahaha");
#else
    if(label == NULL) return;
    watch_qq_user_info_t * info = lv_watch_get_free_ptr(label);
    if(info->remark)
        lv_label_set_text(label, info->remark);
    else
        lv_label_set_text(label, info->nickname);
#endif
}

void qq_stop_record(lv_qq_obj_ext_t * ext)
{
    if(ext->msg_list == NULL) return;
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)lv_obj_get_ext_attr(ext->msg_list);
    if(list_ext->record_cont != NULL) {
        lv_obj_del(list_ext->record_cont);
        list_ext->record_cont = NULL;
        uint32_t size = qq_voice_msg_record_buffer_stop_req();
        Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
        if(VOICE_MSG_AMR_HEAD_SIZE >= size) {
            lv_mem_free(list_ext->buffer);
            list_ext->buffer = NULL;
            return;
        }
    }
}

static uint32_t qq_voice_msg_record_buffer_stop_req(void)
{
    uint32_t duration_ms = 0;
    uint32_t size = 0;
#ifdef BUILD_IN_PC_SIMULATOR /*for pc test*/
    voice_msg_test_record_buffer_stop_req(&size, &duration_ms);
#else
    Hal_Record_Buffer_Stop_Req(&size, &duration_ms);
#endif
    return size;
}

static void qq_voice_msg_record_task_cb(lv_task_t * task)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    if(ext == NULL) return;
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)lv_obj_get_ext_attr(ext->msg_list);
    printf("%s: event %d\n", __FUNCTION__, list_ext->event);
    switch(list_ext->event) {
        case MCI_EVENT_EOS: {
            if(list_ext->record_cont != NULL) {
                lv_obj_del(list_ext->record_cont);
                list_ext->record_cont = NULL;
                uint32_t size = qq_voice_msg_record_buffer_stop_req();
                printf("%s: buffer size %d\n", __FUNCTION__, size);
                Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
                if(VOICE_MSG_AMR_HEAD_SIZE >= size) {
                    lv_mem_free(list_ext->buffer);
                    list_ext->buffer = NULL;
                    return;
                }
                watch_qq_user_info_t * info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(ext->name);
                qq_send_msg(info->openid, QQ_MSG_TYPE_VOICE, 0, list_ext->buffer, size, QQ_VOICE_MSG_MAX_RECORD_DURATION);
            }
        }
        break;
        case MCI_EVENT_ERROR:
            lv_obj_del(list_ext->record_cont);
            list_ext->record_cont = NULL;
            if(list_ext->buffer) {
                lv_mem_free(list_ext->buffer);
                list_ext->buffer = NULL;
            }
            break;
        default:
            break;
    }
}

static void qq_voice_msg_chat_record_cb(MCI_EVNET_T event, MCI_INFO_T info_type, int32_t value)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)lv_obj_get_ext_attr(ext->msg_list);
    if(MCI_EVENT_INFO == event) {
        return;
    }
    list_ext->event = event;
    lv_task_t * record_task = lv_task_create(qq_voice_msg_record_task_cb, 10, LV_TASK_PRIO_HIGH, NULL);
    lv_task_once(record_task);
}

void qq_hold_to_talk_btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_msg_list_ext_t * list_ext = (qq_msg_list_ext_t *)lv_obj_get_ext_attr(ext->msg_list);
    if(LV_EVENT_PRESSED == event) {
        if(list_ext->record_cont == NULL) {
            lv_obj_t * rec_cont = lv_cont_create(lv_obj_get_parent(ext->msg_list), NULL);
            lv_obj_set_size(rec_cont, LV_HOR_RES / 2, LV_VER_RES / 3);
            lv_obj_set_style_local_radius(rec_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
            lv_obj_set_style_local_bg_color(rec_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, QQ_COLOR_BLUE_NORMAL);
            lv_obj_align(rec_cont, NULL, LV_ALIGN_CENTER, 0, 0);
            lv_obj_t * rec_img = lv_img_create(rec_cont, NULL);
            lv_img_set_src(rec_img, ICON_QQ_RECORD_01);
            lv_obj_align(rec_img, rec_cont, LV_ALIGN_CENTER, 0, 0);
            lv_watch_set_free_num(rec_img, 0);
            list_ext->record_cont = rec_cont;
        }
    } else if(LV_EVENT_RELEASED == event) {
        if(list_ext->record_cont != NULL) {
            if(lv_obj_count_children(list_ext->record_cont) == 1) {
                lv_label_set_text_id(ext->name, WATCH_TEXT_ID_QQ_TIME_SHORT);
                lv_anim_t a = {0};
                lv_anim_init(&a);
                lv_anim_set_var(&a, ext->name);
                lv_anim_set_ready_cb(&a, (lv_anim_ready_cb_t)qq_record_time_short_tip_timer_cb);
                lv_anim_set_repeat_count(&a, 1);
                lv_anim_set_time(&a, 1000);
                lv_anim_start(&a);
            } else {
                uint32_t size = qq_voice_msg_record_buffer_stop_req();
                printf("%s: buffer size %d\n", __FUNCTION__, size);
                Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
                if(VOICE_MSG_AMR_HEAD_SIZE >= size) {
                    lv_mem_free(list_ext->buffer);
                    list_ext->buffer = NULL;
                    lv_obj_del(list_ext->record_cont);
                    list_ext->record_cont = NULL;
                    return;
                }
                watch_qq_user_info_t * info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(ext->name);
                uint8_t duration;
                uint8_t num = lv_watch_get_free_num(lv_obj_get_child(list_ext->record_cont, NULL));
                if(num == QQ_VOICE_MSG_MAX_RECORD_DURATION)
                    duration = 1;
                else
                    duration = QQ_VOICE_MSG_MAX_RECORD_DURATION - num;
                qq_send_msg(info->openid, QQ_MSG_TYPE_VOICE, 0, list_ext->buffer, size, duration);
            }
            lv_obj_del(list_ext->record_cont);
            list_ext->record_cont = NULL;
        }
    } else if(LV_EVENT_LONG_PRESSED == event) {
        if(list_ext->record_cont != NULL) {
            lv_anim_t a = {};
            lv_anim_init(&a);
            lv_anim_set_var(&a, lv_obj_get_child(list_ext->record_cont, NULL));
            lv_anim_set_start_cb(&a, (lv_anim_ready_cb_t)qq_msg_speaking_anim);
            lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
            lv_anim_set_time(&a, 500);
            lv_anim_start(&a);

            list_ext->buffer = (uint8_t *)lv_mem_alloc(QQ_VOICE_MSG_MAX_RECORD_SIZE);
            Hal_Audio_Manage_Start_Req(AUDIO_CTRL_PRIORITY_5, voice_msg_audio_ctrl_callback);
#ifdef BUILD_IN_PC_SIMULATOR /*for pc test*/
            voice_msg_test_record_buffer_start_req(list_ext->buffer,
                                                   QQ_VOICE_MSG_MAX_RECORD_SIZE,
                                                   QQ_VOICE_MSG_MAX_RECORD_DURATION * 1000,
                                                   qq_voice_msg_chat_record_cb);
#else
            Hal_Record_Buffer_Start_Req(list_ext->buffer,
                                        QQ_VOICE_MSG_MAX_RECORD_SIZE,
                                        (QQ_VOICE_MSG_MAX_RECORD_DURATION + 1) * 1000,
                                        qq_voice_msg_chat_record_cb);
#endif
        }
    } else if(LV_EVENT_PRESS_LOST == event) {
        printf("%s: press lost, cancel send!!\n", __FUNCTION__);
        if(list_ext->record_cont != NULL) {
            lv_label_set_text_id(ext->name, WATCH_TEXT_ID_QQ_CANCEL_RECORD);
            lv_anim_t a = {0};
            lv_anim_init(&a);
            lv_anim_set_var(&a, ext->name);
            lv_anim_set_ready_cb(&a, (lv_anim_ready_cb_t)qq_record_time_short_tip_timer_cb);
            lv_anim_set_repeat_count(&a, 1);
            lv_anim_set_time(&a, 1000);
            lv_anim_start(&a);
            qq_voice_msg_record_buffer_stop_req();
            Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_5);
            lv_mem_free(list_ext->buffer);
            list_ext->buffer = NULL;
            lv_obj_del(list_ext->record_cont);
            list_ext->record_cont = NULL;
        }
    }
}

void qq_create_chat(lv_obj_t * par, watch_qq_user_info_t * info)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * cont = qq_create_bg_cont(par, LV_OPA_COVER, 0);

    lv_obj_t * back_img = qq_create_back_img(cont, QQ_CHAT);
    lv_obj_t * name_label = lv_label_create(cont, NULL);
    ext->name = name_label;
    lv_label_set_long_mode(name_label, LV_LABEL_LONG_DOT);
    lv_obj_set_width(name_label, LV_HOR_RES - lv_obj_get_width(back_img) - 20);
    lv_label_set_text_id(name_label, WATCH_TEXT_ID_QQ_RECEIVING_MSG);
    lv_label_set_align(name_label, LV_LABEL_ALIGN_CENTER);
    lv_obj_align(name_label, back_img, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
    lv_watch_set_free_ptr(name_label, (void *)info);

#if QQ_UI_TEST
    Hal_Timer_Start(1000, qq_get_msg_timer_cb, NULL, false);
#else
    watch_qq_get_friend_msg_req_t * get_msg_req = (watch_qq_get_friend_msg_req_t *)lv_mem_alloc(sizeof(watch_qq_get_friend_msg_req_t));
    memcpy(get_msg_req->openid, info->openid, 64);
    get_msg_req->lastmsg_time = 0;
    get_msg_req->random = 0;
    get_msg_req->get_msgcnt = MMI_QQ_GET_FRIEND_MSG_ONCE;
    get_msg_req->direction = 1;
    watch_qq_get_friend_msg_req(get_msg_req);
#endif

    lv_obj_t * expression_icon = lv_img_create(cont, NULL);
    lv_img_set_src(expression_icon, ICON_QQ_EXPRESSION);
    lv_obj_set_click(expression_icon, true);
    lv_obj_align(expression_icon, cont, LV_ALIGN_IN_BOTTOM_LEFT, lv_obj_get_height(expression_icon) / 8 + QQ_BACK_IMG_PAD_LEFT, -lv_obj_get_height(expression_icon) / 8 - QQ_PAD_VER);
    lv_obj_set_event_cb(expression_icon, qq_create_expression_btn_event_cb);

    lv_obj_t * hold_btn = lv_btn_create(cont, NULL);
    lv_obj_set_size(hold_btn, (LV_VER_RES - lv_obj_get_width(expression_icon)) * 2 / 3 - QQ_PAD_HOR * 2, lv_obj_get_height(expression_icon));
    lv_obj_set_style_local_bg_color(hold_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, QQ_COLOR_BLUE_NORMAL);
    lv_obj_set_style_local_bg_color(hold_btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, QQ_COLOR_BLUE_PRESSED);
    lv_obj_set_style_local_radius(hold_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 50);
    lv_obj_align(hold_btn, expression_icon, LV_ALIGN_OUT_RIGHT_MID,
                 (LV_VER_RES - lv_obj_get_width(expression_icon) * 9 / 8 - lv_obj_get_width(hold_btn) - QQ_BACK_IMG_PAD_LEFT) / 2 - QQ_PAD_HOR, 0);
    lv_obj_set_event_cb(hold_btn, qq_hold_to_talk_btn_event_cb);

    lv_obj_t * hold_label = lv_label_create(hold_btn, NULL);
    lv_label_set_text_id(hold_label, WATCH_TEXT_ID_QQ_HOLD_TALK);
    lv_obj_align(hold_label, hold_btn, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t * list = qq_msg_list_create(cont, LV_HOR_RES - QQ_PAD_HOR * 2,
                                         lv_obj_get_y(expression_icon) - lv_obj_get_height(back_img) - QQ_PAD_VER - 5);
    lv_obj_set_pos(list, QQ_PAD_HOR, lv_obj_get_height(back_img) + QQ_PAD_VER);
    ext->msg_list = list;
    qq_msg_time_start_update(cont);
}

static void qq_msg_time_update_cb(lv_anim_t * anim)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * list_obj;
    lv_obj_t * time_label;
    if(ext->msg_list) {
        lv_obj_t * scrl = lv_page_get_scrl(ext->msg_list);
        list_obj = lv_obj_get_child(scrl, NULL);
        while(list_obj) {
            time_label = lv_obj_get_child_back(list_obj, NULL);
            if(qq_list_obj_is_label(time_label)) {
                char str[16];
                uint32_t time = lv_watch_get_free_num(time_label);
                qq_get_timestr_from_timestamp(time, str, 16);
                lv_label_set_text(time_label, str);
                lv_obj_realign(time_label);
            }
            list_obj = lv_obj_get_child(scrl, list_obj);
        }
    }
}

static void qq_msg_time_start_update(lv_obj_t * cont)
{
    lv_anim_t a;
    lv_anim_path_t path;

    lv_anim_path_init(&path);
    lv_anim_path_set_cb(&path, lv_anim_path_step);
    lv_anim_init(&a);
    lv_anim_set_path(&a, &path);
    lv_anim_set_var(&a, cont);
    lv_anim_set_time(&a, 0);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_repeat_delay(&a, 60000);
    lv_anim_set_start_cb(&a, qq_msg_time_update_cb);
    lv_anim_start(&a);
}

void qq_get_msg_over(uint32_t time, uint32_t random)
{
    //qq_lastmsg_time = time;
    // qq_lastmsg_random = random;
    lv_qq_obj_ext_t * ext = qq_get_ext();
    if(ext->msg_list == NULL || ext->name == NULL) return;
    qq_msg_list_ext_t * list_ext = lv_obj_get_ext_attr(ext->msg_list);
    watch_qq_user_info_t * user_info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(ext->name);
    if(user_info->remark) lv_label_set_text(ext->name, user_info->remark);
    else lv_label_set_text(ext->name, user_info->nickname);
    lv_obj_realign(ext->name);
    list_ext->getting_msg = false;
}

void qq_add_msg_into_list(lv_ll_t * msg_infos_ll)
{
    lv_qq_obj_ext_t * ext = qq_get_ext();
    if(ext->msg_list == NULL || ext->name == NULL) return;
    watch_qq_user_info_t * user_info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(ext->name);
#if QQ_UI_TEST
    qq_msg_desc_t desc[] = {
        {QQ_MSG_TYPE_TEXT, 1635413792, "Hello!", 6, 0, 0, 0, 1},
        {QQ_MSG_TYPE_TEXT, 1635823792, "可查看联系人信息发起会话和", strlen("可查看联系人信息、发起会话和"), 0, 0, 0, 0},
        {QQ_MSG_TYPE_PHOTO, 1635923792, NULL, 6, 0, 0, 0, 1},
        {QQ_MSG_TYPE_EXPRESSION, 1636023692, qq_expression_list[3].ex_path, 0, 0, 0, 0, 1},
    };
    if(user_info->remark) lv_label_set_text(ext->name, user_info->remark);
    else lv_label_set_text(ext->name, user_info->nickname);
    qq_msg_list_add(ext->msg_list, &desc[0]);
    qq_msg_list_add(ext->msg_list, &desc[1]);
    qq_msg_list_add(ext->msg_list, &desc[2]);
    qq_msg_list_add(ext->msg_list, &desc[3]);
#else
    qq_msg_desc_t desc;
    watch_qq_login_info_t * info = watch_qq_get_last_login_info();
    watch_qq_msg_info_t * node = (watch_qq_msg_info_t *)_lv_ll_get_head(msg_infos_ll);
    watch_qq_msg_element_t * ele_node = NULL;
    while(node) {
        memset(&desc, 0, sizeof(qq_msg_desc_t));
        if(memcmp(node->from_openid, info->openid, 64) == 0)
            desc.direction = 0;
        else if(memcmp(node->from_openid, user_info->openid, 64) == 0)
            desc.direction = 1;
        else {
            node = _lv_ll_get_next(msg_infos_ll, node);
            continue;
        }
        desc.time = node->msg_timestamp;
        desc.seq_id = (uint16_t)(node->msg_seqid >> 16) & (0xFFFF);
        printf("%s:msg_elementcnt = %d seqid = %d\n", __FUNCTION__, node->msg_elementcnt, desc.seq_id);
        if(node->msg_elementcnt > 0) {
            ele_node = (watch_qq_msg_element_t *)_lv_ll_get_head(&node->msg_elements_ll);
            uint8_t node_index = 0;
            while(ele_node) {
                if(ele_node->msg_type == WATCH_QQ_MSG_TYPE_TEXT) {
                    desc.ex_index = MMI_QQ_EXPRESSION_MAX_CNT;
                    if(memcmp(ele_node->msg_content, "[", 1) == 0) {
                        for(uint8_t i = 0; i < MMI_QQ_EXPRESSION_MAX_CNT; i++) {
                            if(memcmp(ele_node->msg_content, qq_expression_list[i].ex_desc, strlen(qq_expression_list[i].ex_desc)) == 0) {
                                desc.type = QQ_MSG_TYPE_EXPRESSION;
                                desc.ex_index = i;
                                break;
                            }
                        }
                        if(desc.ex_index == MMI_QQ_EXPRESSION_MAX_CNT) {
                            desc.type = QQ_MSG_TYPE_TEXT;
                            desc.data = ele_node->msg_content;
                        }
                    } else {
                        desc.type = QQ_MSG_TYPE_TEXT;
                        desc.data = ele_node->msg_content;
                    }
                } else if(ele_node->msg_type == WATCH_QQ_MSG_TYPE_PIC) {
                    desc.type = QQ_MSG_TYPE_PHOTO;
                } else if(ele_node->msg_type == WATCH_QQ_MSG_TYPE_PTT) {
                    desc.type = QQ_MSG_TYPE_VOICE;
                    desc.local_msg = 0;
                    watch_qq_ptt_msg_content_t * ptt_msg = (watch_qq_ptt_msg_content_t *)ele_node->msg_content;
                    desc.data = lv_strdup(ptt_msg->url);
                    desc.duration = ptt_msg->duration;
                    printf("%s: voice dur = %d\n", __FUNCTION__, desc.duration);
                } else {
                    desc.type = QQ_MSG_TYPE_OTHER;
                }
                if(node_index > 0) {
                    desc.time = 0;
                    desc.seq_id = desc.seq_id + 1;
                }
                qq_msg_list_add(ext->msg_list, &desc);
                ele_node = _lv_ll_get_next(&node->msg_elements_ll, ele_node);
                node_index++;
            }
        }
        node = _lv_ll_get_next(msg_infos_ll, node);
    }
    lv_mem_free(info);
#endif
}

void qq_friend_info_send_msg_btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    watch_qq_user_info_t * info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(btn);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    qq_create_chat(ext->friend, info);
}

void qq_friend_info_del_friend_btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * mbox = qq_create_msgbox(ext->friend, WATCH_TEXT_ID_QQ_DEL_FRIEND_CONFIRM, qq_del_friend_confirm_btn_event_cb);
    lv_watch_set_free_ptr(lv_obj_get_parent(mbox), lv_watch_get_free_ptr(btn));
}

void qq_my_friend_list_btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED == event) {
        lv_qq_obj_ext_t * ext = qq_get_ext();
        ext->friend_list_act_btn = btn;
        qq_friend_btn_ext_t * btn_ext = (qq_friend_btn_ext_t *)lv_obj_get_ext_attr(btn);
        watch_qq_user_info_t * info = &btn_ext->info;
#if QQ_UI_TEST == 0
        watch_qq_get_friend_info_req_t * friend_info_req = lv_mem_alloc(sizeof(watch_qq_get_friend_info_req_t));
        memcpy(friend_info_req->openid, info->openid, 64);
        qq_set_get_friend_info_type(QQ_GET_LIST_FRIEND_INFO);
        watch_qq_get_friend_info_req(friend_info_req);
#endif
        lv_obj_t * cont = qq_create_bg_cont(ext->friend, LV_OPA_COVER, 0);

        lv_obj_t * back_img = qq_create_back_img(cont, QQ_FRIEND_INFO);
        lv_obj_t * page = lv_page_create(cont, NULL);
        lv_page_set_scrollbar_mode(page, LV_SCROLLBAR_MODE_OFF);
        lv_obj_set_size(page, LV_HOR_RES, LV_VER_RES - lv_obj_get_height(back_img) - QQ_PAD_VER * 2);
        lv_obj_align(page, cont, LV_ALIGN_IN_TOP_MID, 0, lv_obj_get_height(back_img) + QQ_PAD_VER);
        lv_obj_set_style_local_bg_color(page, LV_PAGE_PART_BG, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_obj_set_style_local_pad_bottom(page, LV_PAGE_PART_SCROLLABLE, LV_STATE_DEFAULT, LV_VER_RES / 20);

        lv_obj_t * head_img = lv_img_create(page, NULL);
        lv_img_set_src(head_img, ICON_QQ_DEF_HEAD_MID);
        lv_obj_align(head_img, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);
        lv_page_glue_obj(head_img, true);

        lv_obj_t * name_label = lv_label_create(page, NULL);
        lv_label_set_text(name_label, info->nickname);
        lv_obj_set_style_local_text_color(name_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_label_set_long_mode(name_label, LV_LABEL_LONG_DOT);
        lv_obj_set_width(name_label, LV_HOR_RES * 2 / 3);
        lv_label_set_align(name_label, LV_LABEL_ALIGN_CENTER);
        lv_obj_align(name_label, head_img, LV_ALIGN_OUT_BOTTOM_MID, 0, lv_obj_get_height(head_img) / 4);
        lv_page_glue_obj(name_label, true);

        lv_obj_t * num_label = lv_label_create(page, NULL);
        lv_label_set_text(num_label, "12345678");
        lv_obj_set_style_local_text_color(num_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_align(num_label, name_label, LV_ALIGN_OUT_BOTTOM_MID, 0, lv_obj_get_height(head_img) / 4);
        lv_page_glue_obj(num_label, true);

        lv_obj_t * send_msg_btn = lv_btn_create(page, NULL);
        lv_obj_set_size(send_msg_btn, LV_HOR_RES * 5 / 6 - QQ_PAD_HOR * 2, LV_VER_RES / 5 - QQ_PAD_VER);
        lv_obj_set_style_local_bg_color(send_msg_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_color(send_msg_btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_WHITE);
        lv_obj_set_style_local_radius(send_msg_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 50);
        lv_obj_set_event_cb(send_msg_btn, qq_friend_info_send_msg_btn_event_cb);
        lv_watch_set_free_ptr(send_msg_btn, (void *)info);
        lv_obj_t * send_msg_label = lv_label_create(send_msg_btn, NULL);
        lv_label_set_text_id(send_msg_label, WATCH_TEXT_ID_QQ_SEND_MSG);
        lv_obj_set_style_local_text_color(send_msg_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_obj_align(send_msg_btn, num_label, LV_ALIGN_OUT_BOTTOM_MID, 0, lv_obj_get_height(head_img) / 3);
        lv_page_glue_obj(send_msg_btn, true);

        lv_obj_t * del_btn = lv_btn_create(page, send_msg_btn);
        lv_obj_set_style_local_bg_color(del_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, QQ_COLOR_RED_NORMAL);
        lv_obj_set_style_local_bg_color(del_btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, QQ_COLOR_RED_PRESSED);
        lv_obj_set_event_cb(del_btn, qq_friend_info_del_friend_btn_event_cb);
        lv_watch_set_free_ptr(del_btn, (void *)info);
        lv_obj_t * del_label = lv_label_create(del_btn, NULL);
        lv_label_set_text_id(del_label, WATCH_TEXT_ID_QQ_DEL_FRIEND);
        lv_obj_set_style_local_text_color(del_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_align(del_btn, send_msg_btn, LV_ALIGN_OUT_BOTTOM_MID, 0, lv_obj_get_height(head_img) / 4);
        lv_page_glue_obj(del_btn, true);

        qq_create_bg_cont(ext->friend, LV_OPA_90, WATCH_TEXT_ID_QQ_PULLING_DATA);
#if QQ_UI_TEST
        Hal_Timer_Start(1000, qq_get_friend_info_timer_cb, NULL, false);
#endif
    } else if(LV_EVENT_DELETE == event) {
        printf("%s:clean up btn ext\n", __FUNCTION__);
        qq_friend_btn_ext_t * btn_ext = lv_obj_get_ext_attr(btn);
        if(btn_ext->info.headurl) lv_mem_free(btn_ext->info.headurl);
        if(btn_ext->info.nickname) lv_mem_free(btn_ext->info.nickname);
        if(btn_ext->info.remark) lv_mem_free(btn_ext->info.remark);
    }
}

void qq_friend_info_update(watch_qq_user_info_t * info)
{
    printf("%s:qqid = %s\n", __FUNCTION__, info->qqid);
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * pulling_cont = lv_obj_get_child(ext->friend, NULL);
    lv_obj_del(pulling_cont);
    lv_obj_t * page = lv_obj_get_child(lv_obj_get_child(ext->friend, NULL), NULL);
    lv_obj_t * scrllabel = lv_page_get_scrollable(page);
    lv_obj_t * del_btn = lv_obj_get_child(scrllabel, NULL);
    lv_obj_t * msg_btn = lv_obj_get_child(scrllabel, del_btn);
    lv_obj_t * num_label =  lv_obj_get_child(scrllabel, msg_btn);
    lv_label_set_text(num_label, info->qqid);
    lv_obj_realign(num_label);
    watch_qq_user_info_t * btn_info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(del_btn);
    memcpy(btn_info->qqid, info->qqid, strlen(info->qqid));
#if QQ_UI_TEST == 0
    char * path = watch_qq_get_friend_head_path(info->openid);
    if(path != NULL) {
        lv_obj_t * img =  lv_obj_get_child_back(scrllabel, NULL);
        lv_img_set_src(img, path);
        lv_mem_free(path);
    } else {
        watch_qq_get_data_req_t * get_data_req = lv_mem_alloc(sizeof(watch_qq_get_data_req_t));
        get_data_req->url = lv_strdup(info->headurl);
        qq_add_get_data_info(QQ_DATA_FRIEND_HEAD, 0, get_data_req->url);
        watch_qq_get_data_req(get_data_req);
    }
#else
    Hal_Timer_Start(200, qq_get_friend_info_timer_cb, (void *)btn_info, false);
#endif
}

void qq_friend_info_update_headimg(void * src)
{
    if(!strncmp(src, ICON_QQ_DEF_HEAD, strlen(ICON_QQ_DEF_HEAD)))
        return;
    lv_qq_obj_ext_t * ext = qq_get_ext();
    watch_qq_user_info_t * btn_info;
    uint8_t child_cnt = lv_obj_count_children(ext->friend);
    printf("%s: child cnt = %d!\n", __FUNCTION__, child_cnt);
    if(child_cnt == 1)
        return;
    else if(child_cnt == 2) {
        lv_obj_t * head_img = lv_obj_get_child_back(ext->friend_list_act_btn, NULL);
        lv_img_set_src(head_img, src);
        qq_friend_btn_ext_t * btn_ext = lv_obj_get_ext_attr(ext->friend_list_act_btn);
        btn_info = &btn_ext->info;
    } else {
        lv_obj_t * page = lv_obj_get_child(lv_obj_get_child(ext->friend, NULL), NULL);
        lv_obj_t * scrllabel = lv_page_get_scrollable(page);
        lv_obj_t * img =  lv_obj_get_child_back(scrllabel, NULL);
        lv_img_set_src(img, src);

        lv_obj_t * del_btn = lv_obj_get_child(scrllabel, NULL);
        btn_info = (watch_qq_user_info_t *)lv_watch_get_free_ptr(del_btn);
    }
    watch_qq_friend_info_t info;
    memset(&info, 0, sizeof(watch_qq_friend_info_t));
    strncpy(info.openid, btn_info->openid, 64);
    strncpy(info.qqid, btn_info->qqid, QQ_ID_LEN);
    strncpy(info.headpath, (char *)src, QQ_HEAD_PATH_LEN);
    watch_qq_add_friend(&info);
}

void qq_friend_list_update_img_head(void)
{
    char * path = NULL;
    lv_qq_obj_ext_t * ext = qq_get_ext();
    lv_obj_t * head_img = lv_obj_get_child_back(ext->friend_list_act_btn, NULL);
    qq_friend_btn_ext_t * btn_ext = lv_obj_get_ext_attr(ext->friend_list_act_btn);
    path = watch_qq_get_friend_head_path(btn_ext->info.openid);
    if(!strncmp(lv_img_get_src(head_img), ICON_QQ_DEF_HEAD, strlen(ICON_QQ_DEF_HEAD))) {
        if(path != NULL) {
            lv_img_set_src(head_img, path);
        }
    }
    if(ext->recent_list != NULL) {
        lv_obj_t * btn = lv_list_get_next_btn(ext->recent_list, NULL);
        qq_friend_btn_ext_t * contact_btn_ext = NULL;
        while(btn) {
            contact_btn_ext = lv_obj_get_ext_attr(btn);
            head_img = lv_obj_get_child_back(btn, NULL);
            if(!strncmp(contact_btn_ext->info.openid, btn_ext->info.openid, 64) &&
                    !strncmp(lv_img_get_src(head_img), ICON_QQ_DEF_HEAD, strlen(ICON_QQ_DEF_HEAD))) {
                if(path != NULL) {
                    lv_img_set_src(head_img, path);
                    break;
                }
            }
            btn = lv_list_get_next_btn(ext->recent_list, btn);
        }
    }
    if(path != NULL)
        lv_mem_free(path);
}
#endif /*USE_LV_WATCH_QQ*/



